require 'depac-deployment/environment_configuration'
require 'depac-deployment/helper'
require 'depac-deployment/helper_cbt'
require 'depac-deployment/configure'
require 'depac-common/constants'
require 'depac-common/constants_cbt'
require 'depac-common/deployment_cbt'
require 'depac-common/utils'

#Start point for updateEnv
module Depac 
module CBT_UPDATE 


def self.updateEnvironment(envConfigObject, updateconfigpath, buildlabel, outputFilePath)

     existNodeInfoMapFull=Utils.buildNodeInfoMap(envConfigObject)
  
     if updateconfigpath == nil 
             Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment handle update without custom updateconfig....................")
             $deployment.getArtifacts(existNodeInfoMapFull, buildlabel, envConfigObject)
             $deployment.deployApp(existNodeInfoMapFull, buildlabel, envConfigObject, true, 20)
     else
            if (File.exists?(updateconfigpath))
                  updateconfig = YAML.load_file(updateconfigpath)
                  $deployment.artifactMapPath=updateconfig['artifactLocationMapPath']                  
                  if updateconfig['components'] == nil  
                         Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment handle update without components defind in updateconfig....................")
                         $deployment.getArtifacts(existNodeInfoMapFull, buildlabel, envConfigObject)
                         $deployment.deployApp(existNodeInfoMapFull, buildlabel, envConfigObject, true, updateconfig['delay'])
                  else
                      Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment handle update with components defind in updateconfig....................")
                      #since customer specified componets and IPs we just need to 
                      #1. getUpdateArtifacts based on components
                      #2. create Artifact location folder
                      #3. call $deployment.downloadArtifacts(aggregatedArtifactMap, buildlabel)
                      #4. get hited node
                      #5. remove no-hited node and store result to nodeInfoMapUpdate
                      #6. call deployApp(nodeInfoMapUpdate, buildlabel, envconfig, isUpdate=true, sleepTime=?)
                      aggregatedArtifactMap=Depac::CBT_UPDATE::getUpdateArtifacts(updateconfig)
                      if aggregatedArtifactMap['wars'].size >0
                           
                                 artifactsDir=Depac::DeploymentConstants_CBT::DefaultArtifactLocation+"/#{buildlabel}"
                                 
                                 if File.directory?(artifactsDir)
                                      removeCMD="rm -rf #{artifactsDir}"
                                      Utils.logged_exec(removeCMD,"Depac::CBT_UPDATE.updateEnvironment remove existed artifactsDir......", true) 
                                 end
                                 
                                 createCMD="mkdir -p  #{artifactsDir}/web;mkdir -p  #{artifactsDir}/temp;mkdir -p   #{artifactsDir}/schema" 
                                 Utils.logged_exec(createCMD,"Depac::CBT_UPDATE.updateEnvironment create artifactsDir..........", true) 
                                 
                                 $deployment.downloadArtifacts(aggregatedArtifactMap, buildlabel) 
                                 
                                 update_nodeInfoMap = Depac::CBT_UPDATE::regenerateNodeInfoMap(existNodeInfoMapFull, updateconfig, false)
                                 
                                 $deployment.aggregatedArtifactMap=aggregatedArtifactMap
                                 $deployment.artifactMapPath=updateconfig['artifactLocationMapPath']
                                 Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment aggregatedArtifactMap is #{$deployment.aggregatedArtifactMap}....................")
                                 Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment artifactLocationMapPath is #{$deployment.artifactMapPath}....................")
                                 $deployment.deployApp(update_nodeInfoMap, buildlabel, envConfigObject, true, updateconfig['delay'])
                      end
                  end
            end
     end
end

  
# @aggregatedArtifactMap={"wars"=>{ "trade"=>{"location" => "war package location",
#                                           "packageName" => "trade-web",
#                                           "localLocation" => ""
#                                          } 
#                                }    
#                        }

def self.getUpdateArtifacts(updateconfig)
       aggregateArtifactMap={
                        "wars"=>nil
                      }
      
       _aggregateArtifactMap=Hash.new
        
        artifactMap=YAML.load_file(File.expand_path(updateconfig['artifactLocationMapPath']))
          
        #generate war collection
        updateconfig['components'].each do |componentObj|
              if componentObj['war'] !=nil
                _location=$deployment.getArtifactLocation(artifactMap, "wars", componentObj['war'])
                _artifact=$deployment.getArtifactName(componentObj['war'], "war", Depac::DeploymentConstants_CBT::WAR_FORMAT)  
                _aggregateArtifactMap[componentObj['war']]={"location" => _location,
                                                "packageName" => _artifact,
                                                "localLocation" => nil
                                               }   
              end                 
        end  
        
        aggregateArtifactMap['wars']=_aggregateArtifactMap

        _aggregateArtifactMap=Hash.new 
       
        #generate schema collection
        updateconfig['components'].each do |componentObj|
               if componentObj['schema'] !=nil
                  _location=$deployment.getArtifactLocation(artifactMap, "schema", componentObj['schema'])
                  _artifact=$deployment.getArtifactName(componentObj['schema'], "schema", nil)  
                  _aggregateArtifactMap[componentObj['schema']]={"location" => _location,
                                                  "packageName" => _artifact,
                                                  "localLocation" => nil
                                                 }  
               end                  
        end  
        
        aggregateArtifactMap['schema']=_aggregateArtifactMap
          
        return  aggregateArtifactMap        
end

def self.regenerateNodeInfoMap(nodeInfoMap, updateconfig, addnew)
     new_nodeInfoMap=Hash.new
     if nodeInfoMap!=nil && updateconfig['components'] !=nil   
         nodeInfoMap.each do |role, nodeInfoArray|
               if role.include?('app')
                 
                 nodeInfoArray.each do |node|
                    new_wars=nil
                    new_linkto=nil
                    updateconfig['components'].each do |componentObj| 
                         if componentObj['war'] !=nil                      
                            if componentObj['ips'] !=nil 
                                    if componentObj['ips'].include?(node['IP']) && node['wars'].include?(componentObj['war'])
                                                if new_wars==nil
                                                      new_wars=componentObj['war']
                                                else
                                                      new_wars=new_wars+","+componentObj['war']
                                                end
                                                
                                                if componentObj['linkto'] !=nil && addnew
                                                    new_linkto=componentObj['linkto']
                                                end
                                    end
                            else
                                  
                                  if node['wars'].include?(componentObj['war'])
                                             if new_wars==nil
                                                  new_wars=componentObj['war']
                                             else
                                                  new_wars=new_wars+","+componentObj['war']
                                             end
                                  end
                            end


                    
                            if new_wars !=nil
                      
                           
                              if new_nodeInfoMap[role] == nil
                                   new_nodeInfoMap[role]=Array.new
                              end
                          
                              _node=node.clone
                              _node['wars']=new_wars
                              
                          
                              if addnew && componentObj['linkto'] !=nil
                                   _node['linkto']=componentObj['linkto']                                
                              end

                              new_nodeInfoMap[role].push(_node)  
                           end
                        end
                      end
                    end
                    Depac::Log.write("INFO", "Depac::CBT_UPDATE::regenerateNodeInfoMap regenerate role #{role} .....#{new_nodeInfoMap[role]}")              
                   elsif role.include?('db')
                         if addnew
                           nodeInfoArray.each do |node|
                                        new_schemas=nil
                                        
                                        updateconfig['components'].each do |componentObj| 
                                              if componentObj['schema'] !=nil                      
                                                if componentObj['ips'] !=nil 
                                                        if componentObj['ips'].include?(node['IP']) && node['schema'].include?(componentObj['schema'])
                                                                    if new_schemas==nil
                                                                         new_schemas=componentObj['schema']
                                                                    else
                                                                         new_schemas=new_schemas+","+componentObj['schema']
                                                                    end
                                                        end
                                                else
                                                      
                                                      if node['schema'].include?(componentObj['schema'])
                                                                 if new_schemas==nil
                                                                      new_schemas=componentObj['schema']
                                                                 else
                                                                      new_schemas=new_schemas+","+componentObj['schema']
                                                                 end
                                                      end
                                                end
                                              end
                                        end
                                        
                                        if new_schemas !=nil
                                              if new_nodeInfoMap[role] == nil
                                                       new_nodeInfoMap[role]=Array.new
                                              end
                                              
                                              _node=node.clone
                                              _node['schema']=new_schemas
                                              new_nodeInfoMap[role].push(_node)   
                                        end
                                        
                       end
                    else
                             new_nodeInfoMap[role]=nodeInfoArray
                             Depac::Log.write("INFO", "Depac::CBT_UPDATE::regenerateNodeInfoMap copy role #{role} directly.....#{new_nodeInfoMap[role]}")
                    end
               else      
                 new_nodeInfoMap[role]=nodeInfoArray
                 Depac::Log.write("INFO", "Depac::CBT_UPDATE::regenerateNodeInfoMap copy role #{role} directly.....#{new_nodeInfoMap[role]}") 
               end
         end  
     end
     Depac::Log.write("INFO", "Depac::CBT_UPDATE::regenerateNodeInfoMap finial new nodeInfoMap is: .....#{new_nodeInfoMap}") 
     return new_nodeInfoMap
end


def self.addNewComponent(envConfigObject, updateconfigpath, buildlabel)
            
            Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent ....................")
            
            existNodeInfoMapFull=Utils.buildNodeInfoMap(envConfigObject)
            
            if (File.exists?(updateconfigpath))
                    updateconfig = YAML.load_file(updateconfigpath)
                    Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: get updateconfig is #{updateconfig} ....................")
                    $deployment.artifactMapPath=updateconfig['artifactLocationMapPath']                  

                    aggregatedArtifactMap=Depac::CBT_UPDATE::getUpdateArtifacts(updateconfig)
                    if aggregatedArtifactMap['wars'].size >0
                             
                                   artifactsDir=Depac::DeploymentConstants_CBT::DefaultArtifactLocation+"/#{buildlabel}"
                                   
                                   if File.directory?(artifactsDir)
                                        removeCMD="rm -rf #{artifactsDir}"
                                        Utils.logged_exec(removeCMD,"Depac::CBT_UPDATE.updateEnvironment remove existed artifactsDir......", true) 
                                   end
                                   
                                   createCMD="mkdir -p  #{artifactsDir}/web;mkdir -p  #{artifactsDir}/temp;mkdir -p   #{artifactsDir}/schema" 
                                   Utils.logged_exec(createCMD,"Depac::CBT_UPDATE.updateEnvironment create artifactsDir..........", true) 
                                   
                                   $deployment.downloadArtifacts(aggregatedArtifactMap, buildlabel) 
 
                                   #first need to merge the update componet into current existNodeInfoMap  
                                   existNodeInfoMapFull.each do |role, nodeInfoArray|
                                         if role.include?('app')
                                               nodeInfoArray.each do |node|
                                                 updateconfig['components'].each do |newcomponent|
                                                      if newcomponent['war'] !=nil
                                                         if newcomponent['ips'] !=nil
                                                                if newcomponent['ips'].include?(node['IP'])  
                                                                       Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: target server #{node['IP']} not include component #{newcomponent['war']}, add it!....................")                
                                                                       node['wars']=node['wars']+","+newcomponent['war'] unless node['wars'].include?(newcomponent['war'])        
                                                                end
                                                         else     
                                                                  Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: target server #{node['IP']} not include component #{newcomponent['war']}, add it!....................")                      
                                                                  node['wars']=node['wars']+","+newcomponent['war'] unless node['wars'].include?(newcomponent['war'])
                                                         end 
                                                      end                                                 
                                                 end
                                               end                                        
                                         end  
                                         
                                        if role.include?('db')
                                                nodeInfoArray.each do |node|
                                                            updateconfig['components'].each do |newcomponent|
                                                                             if newcomponent['schema'] !=nil
                                                                                              if newcomponent['ips'] !=nil
                                                                                                     if newcomponent['ips'].include?(node['IP'])  
                                                                                                            Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: target server #{node['IP']} not include component #{newcomponent['schema']}, add it!....................")                
                                                                                                            node['schema']=node['schema']+","+newcomponent['schema'] unless node['schema'].include?(newcomponent['schema'])        
                                                                                                     end
                                                                                              else     
                                                                                                       Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: target server #{node['IP']} not include component #{newcomponent['schema']}, add it!....................")                      
                                                                                                       node['schema']=node['schema']+","+newcomponent['schema'] unless node['schema'].include?(newcomponent['schema'])
                                                                                              end 
                                                                             end                                                 
                                                           end
                                               end                                        
                                        end  
                                   end
                                   
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE:: existNodeInfoMap before regenerateNodeInfoMap is #{existNodeInfoMapFull}....................")
                                                                   
                                   update_nodeInfoMap = Depac::CBT_UPDATE::regenerateNodeInfoMap(existNodeInfoMapFull, updateconfig, true)
                            
                                  
                                   
                                   $deployment.aggregatedArtifactMap=aggregatedArtifactMap
                                   $deployment.artifactMapPath=updateconfig['artifactLocationMapPath']
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment aggregatedArtifactMap is #{$deployment.aggregatedArtifactMap}....................")
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE::updateEnvironment artifactLocationMapPath is #{$deployment.artifactMapPath}....................")
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE::regenerateNodeInfoMap is #{update_nodeInfoMap}....................")
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE:: existNodeInfoMap after regenerateNodeInfoMap is #{existNodeInfoMapFull}....................")
                                   
                                   #need to configure Host
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: start configureHostMapping!....................")       
                                   $deployment.configureHostsMapping(update_nodeInfoMap)
                                   #need to deploySchema
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent: start deploy schema!....................") 
                                   $deployment.deploySchema(update_nodeInfoMap, buildlabel, envConfigObject)
                                     
                                   
                                   $deployment.deployApp(update_nodeInfoMap, buildlabel, envConfigObject, true, updateconfig['delay'])
                                    
                                   Depac::Log.write("INFO", "Depac::CBT_UPDATE::addNewComponent nodeInfoMap after finish deploy is #{existNodeInfoMapFull}....................")
                                      
                                   Utils.updateConfigWithNodeInformation(envConfigObject, existNodeInfoMapFull)      
                    end
                    
              end

end

end
end
